#include <stdio.h>
#include <string.h>

// 结构体类型定义方式一： 普通定义
struct struct_01 {
    double height;              // 定义时每个结构体成员之间分号隔开
    char name[50];
    int age;
    char (*say)(char *);        // 成员为函数指针
    struct struct_01 *sct_self; // 指向结构体自身的指针，自引用结构体
};

// 结构体定义方式二：定义并初始化变量
//
// 只要制定了结构体名称， 这个结构体就可以用于定义其他变量
struct struct_02 {
    char item01[10];
    int item02;
    short item03;
} sct_01 = {"abc", 12}, 
  sct_02 = {.item01 = "def", .item03 = 23};

// 结构体定义方式三：匿名结构体
// 
// 这种方式定义的结构体不能用于定义其他变量，
// 只有初始化的变量是定义的结构体类型
struct {
    int item01;
    char item02[20];
    short item03;
} sct_03 = {.item02 = "abc"}; // sct_03是一个变量名， 不是类型名

// 结构体定义方式四：定义结构体时使用typedef
//
// 这种方式定义的结构体在使用时不需要加struct关键字
typedef struct sct_004{
    int item01;
    char item02[20];
    struct sct_004 *item03;
} struct_04; // struct_04 是一个类型名， 不是变量名

int main(int argc, char *argv[])
{
    // 结构体变量初始化方式一：顺序初始化
    // 
    // 初始化结构体变量sct_01
    // 初始化变量成员时， 初始值之间逗号分隔
    // 初始化结构体成员可以全部初始化， 也可以部分初始化

    struct struct_01 sct_01 = {
        12.5, "sct 01 name", 23, 
    };
    
    printf("sct 01 name: %s\n", sct_01.name);
    // -----------------------------------------------

    // 结构体变量初始化方式二：指定成员初始化
    //
    // 初始值之间用逗号分隔
    // 成员使用.操作符指定
    struct struct_01 sct_02 = {
        .name = "sct 02 name",
        .age = 35,
    };

    printf("sct 02 name: %s\n", sct_02.name);
    // -----------------------------------------------
    
    // 结构体变量初始化方式三：采用结构体整体赋值的方式初始化
    //
    // 这种方式可以顺序初始化， 也可以指定成员初始化
    struct struct_01 sct_03;
    sct_03 = (struct struct_01){
        .height = 12.5, .name = "sct 03 name",
    };

    printf("sct 03 name: %s\n", sct_03.name);
    

    struct_04 sct_04;
    struct_04 sct_05;
    memset(&sct_04, 0, sizeof(sct_04));
    sct_04.item03 = &sct_05;
    printf("%p\n", sct_04.item03);

    return 0;
}
